home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Pascal Super Library
/
Pascal Super Library (CW International)(1997).bin
/
LIBRARY
/
CMPLTPAS
/
JTERM.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1988-07-24
|
9KB
|
232 lines
{--------------------------------------------------------------}
{ JTERM }
{ }
{ by Jeff Duntemann }
{ Turbo Pascal V5.0 }
{ Last update 7/24/88 }
{ }
{ This is an interrupt-driven "dumb terminal" program for the }
{ PC. It illustrates the use of Turbo Pascal's INTERRUPT }
{ procedures, and in a lesser fashion the use of serial port }
{ hardware. It is currently hardwired to COM1 for simplicity's}
{ sake. }
{ }
{ From: COMPLETE TURBO PASCAL 5.0 by Jeff Duntemann }
{ Scott, Foresman & Co., Inc. 1988 ISBN 0-673-38355-5 }
{--------------------------------------------------------------}
PROGRAM JTerm;
USES DOS,CRT;
CONST
COM1INT = 12; { Vector # for COM1: (IRQ4) }
{ 8250 control registers, masks, etc. }
RBR = $3F8; { 8250 Receive Buffer Register }
THR = $3F8; { 8250 Transmit Holding Register }
LCR = $3FB; { 8250 Line Control Register }
IER = $3F9; { 8250 Interrupt Enable Register }
MCR = $3FC; { 8250 Modem Control Register }
LSR = $3FD; { 8250 Line Status Register }
DLL = $3F8; { 8250 Divisor Latch LSB }
DLM = $3F9; { 8250 Divisor Latch MSB }
DLAB = $80; { 8250 Divisor Latch Access Bit }
BAUD300 = 384; { Value for 300 baud operation }
BAUD1200 = 96; { Value for 1200 baud operation }
NOPARITY = 0; { Comm format value for no parity }
BITS8 = $03; { Comm format value for 8 bits }
DTR = $01; { Value for Data Terminal Ready }
RTS = $02; { value for Ready To Send }
OUT2 = $08; { Bit that enables adapter interrupts }
{ 8259 control registers, masks, etc. }
OCW1 = $21; { 8259 Operation Control Word 1 }
OCW2 = $20; { 8259 Operation Control Word 2 }
IRQ4 = $10; { Mask to turn IRQ4 interrupts on/off }
TYPE
CircularBuffer = ARRAY[0..1023] OF Char; { A 1K input buffer }
VAR
Quit : Boolean; { Flag for exiting the program }
HiBaud : Boolean; { True if 1200 baud is being used }
KeyChar : Char; { Character from keyboard }
CommChar : Char; { Character from the comm port }
Divisor : Word; { Divisor value for setting baud rate }
Clearit : Byte; { Dummy variable }
Buffer : CircularBuffer; { Our incoming character buffer }
LastRead, { Index of the last character read }
LastSaved : Integer; { Index of the last character stored }
NoShow : SET OF Char; { Don't show characters set }
OldVector : Pointer; { Global storage slot for the old }
{ interrupt vector }
{$I SHOWHELP.SRC} { JTerm's minimal help system }
PROCEDURE EnableInterrupts;
INLINE($FB);
{->>>>Incoming (Interrupt Service Routine)<<<<-----------------}
{ }
{ This is the ISR (interrupt Service Routine) for COM1. Note: }
{ DO NOT call this routine directly; you'll crash hard. The }
{ only way Incoming takes control is when a character coming }
{ in from the modem triggers a hardware interrupt from the }
{ serial port chip, the 8250 UART. Note that the register }
{ pseudo-parameters are not needed here, and you could omit }
{ them. However, omitting them doesn't really get you any }
{ more speed or reliability. }
{--------------------------------------------------------------}
PROCEDURE Incoming(Flags,CS,IP,AX,BX,CX,DX,SI,DI,DS,ES,BP : Word);
INTERRUPT;
BEGIN
{ Our first job is to enable interrupts during the ISR: }
EnableInterrupts;
{ The first "real work" we do is either wrap or increment the index }
{ of the last character saved. If the index is "topped out" at }
{ 1023, we force it to zero. This makes the 1024-byte buffer }
{ "circular," in that once the index hits the end, it rolls over to }
{ the beginning again. }
IF LastSaved >= 1023 THEN LastSaved := 0 ELSE Inc(LastSaved);
{ Next, we read the actual incoming character from the serial port's}
{ one-byte holding buffer: }
Buffer[LastSaved] := Char(Port[RBR]);
{ Finally, we must send a control byte to the 8259 interrupt }
{ controller, telling it that the interrupt is finished: }
Port[OCW2] := $20; { Send EOI byte to 8259 }
END;
{$F+}
PROCEDURE JTermExitProc;
BEGIN
Port[IER] := 0; { Disable interrupts at 8250 }
Port[OCW1] := Port[OCW1] OR IRQ4; { Disable IRQ4 at 8259 }
Port[MCR] := 0; { Bring the comm line down }
SetIntVec(Com1Int,OldVector); { Restore previously saved vector }
END;
{$F-}
PROCEDURE SetupSerialPort;
BEGIN
LastRead := 0; { Initialize the circular buffer pointers }
LastSaved := 0;
Port[IER] := 0; { Disable interrupts while we're setting them up }
GetIntVec(Com1Int,OldVector); { Save old IRQ4 vector }
ExitProc := @JTermExitProc; { Hook exit proc into chain }
SetIntVec(Com1Int,@Incoming); { Put ISR address into vector table }
Port[LCR] := Port[LCR] OR DLAB; { Set up 8250 to set baud rate }
Port[DLL] := Lo(Divisor); { Set baud rate divisor }
Port[DLM] := Hi(Divisor);
Port[LCR] := BITS8 OR NOPARITY; { Set word length and parity }
Port[MCR] := DTR OR RTS OR OUT2; { Enable adapter, DTR, & RTS }
Port[OCW1] := Port[OCW1] AND (NOT IRQ4); { Turn on 8259 IRQ4 ints }
Clearit := Port[RBR]; { Clear any garbage from RBR }
Clearit := Port[LSR]; { Clear any garbage from LSR }
Port[IER] := $01; { Enable interrupt on received character }
END;
FUNCTION InStat : Boolean;
BEGIN
IF LastSaved <> LastRead THEN InStat := True
ELSE InStat := False;
END;
FUNCTION InChar : Char; { Bring in the next character }
{ from the ring buffer }
BEGIN
IF LastRead >= 1023 THEN LastRead := 0
ELSE LastRead := Succ(LastRead);
InChar := Buffer[LastRead];
END;
PROCEDURE OutChar(Ch : Char); { Send a character to the comm port }
BEGIN
Port[THR] := Byte(Ch) { Put character ito Transmit Holding Register }
END;
{>>>>>JTERM MAIN PROGRAM<<<<<}
BEGIN
HiBaud := True; { JTerm defaults to 1200 baud; if "300" }
Divisor := BAUD1200; { is entered after "JTERM" on the command }
IF ParamCount > 0 THEN { line, then 300 baud is used instead. }
IF ParamStr(1) = '300' THEN
BEGIN
HiBaud := False;
Divisor := BAUD300
END;
DirectVideo := True;
NoShow := [#0,#127]; { Don't display NUL or RUBOUT }
SetupSerialPort; { Set up serial port & turn on interrupts }
ClrScr;
Writeln('>>>JTERM by Jeff Duntemann');
Quit := False; { Exit JTERM when Quit goes to True }
REPEAT
IF InStat THEN { If a character comes in from the modem }
BEGIN
CommChar := InChar; { Go get character }
CommChar := Char(Byte(CommChar) AND $7F); { Mask off high bit }
IF NOT (CommChar IN NoShow) THEN { If we can show it,}
Write(CommChar) { then show it! }
END;
IF KeyPressed THEN { If a character is typed at the keyboard }
BEGIN
KeyChar := ReadKey; { First, read the keystroke }
IF KeyChar = Chr(0) THEN { We have an extended scan code here }
BEGIN
KeyChar := ReadKey; { Read second half of extended code }
CASE Ord(KeyChar) OF
59 : ShowHelp; { F1 : Display help screen }
END { CASE }
END
ELSE
CASE Ord(KeyChar) OF
24 : Quit := True; { Ctrl-X: Exit JTerm }
26 : ClrScr; { Ctrl-Z: Clear the screen }
ELSE OutChar(KeyChar)
END; { CASE }
END
UNTIL Quit
END.